/**
 * 
 */
package com.android.dwt.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.Service;
import android.app.PendingIntent.CanceledException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.widget.Toast;

import com.android.dwt.MyLocationManager;
import com.android.dwt.MyReceiver;
import com.android.dwt.Position;
import com.android.dwt.TaskItem;
import com.android.dwt.data.GTDApp;
import com.android.dwt.ui.MainAct;
import com.android.dwt.util.C;

/**
 * @author xiang
 *
 */
public class DWTService extends Service {
	
	public static final String GPS_ACTION = "com.android.dwt.GPS";
	public static float ALERT_RADIUS = 1000f;
	public static final String ALARMS = "com.android.dwt.alarms";
	public static final String SP_ALARM = "alarms";
	public static final int MODE = MODE_PRIVATE;
	private final String TAG = "DWTService";
	private final SimpleDateFormat mSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	
	private final MyBinder mBinder = new MyBinder();
	private AlarmManager mAlarmMgr;
	private ArrayList<Calendar> mCalRemind = new ArrayList<Calendar>();
	private ArrayList<Long> mID = new ArrayList<Long>();
	private GTDApp mGa;
	private MyLocationManager mMyLocationMgr;
	private Timer mTimer = new Timer();
	private MyReceiver mReceiver = new MyReceiver();
	private Thread mThread;
	private MyHandler mHandler;
	private LocationManager mLocationMgr;
	
	
	private class MyHandler extends Handler {
		
		@Override
		public void handleMessage(Message msg) {
			
//			super.handleMessage(msg);
			
			switch (msg.what) {
			
    			case C.GPS.GPS_ALERT:			// Enable location remind
    				
    				Log.e(TAG, "will enable location alert!");
    				
    				mGa.mPosRemind = true;
    				
    				mMyLocationMgr.bindGPS();
    				
    				detectGpsStatus();
    				
    				break;
    				
    			case C.GPS.GPS_UNALERT:		// Disable location alert
    				
    				Log.e(TAG, "will disable location alert!");
    				
    				mGa.mPosRemind = false;
    				
    				if (mTimer != null) {
    					
    					Log.e(TAG, "$mTimer is not null, and will be canceled!");
    					
    					mTimer.cancel();
    					mTimer = null;
    				}
    				
    				mMyLocationMgr.unbindGPS();
    				
    				break;
    				
    			case C.GPS.GPS_ENABLED:
    				
    				Log.e(TAG, "gps is enabled!");
					
					mMyLocationMgr.reBindGPS();
					
					if (mTimer != null) {
						
						Log.e(TAG, "timer is not null, and will be canceled!");
						
						mTimer.cancel();
						mTimer = null;
					}
					
					/*if (mThread.isAlive()) {
    					
    					Log.e(TAG, "thread is alive!");
    					
    				} else {
    					
    					Log.e(TAG, "thread is dead!");
    				}*/
					
//					Log.e(TAG, Thread.currentThread().getName());
					
    				break;
    				
    			case C.GPS.GPS_DISABLED:
    				
    				Log.e(TAG, "gps is disabled, you should open it!");
    				
    				/*Intent i = new Intent(DWTService.this, MyReceiver.class);
    				i.setAction(GPS_ACTION);
    				
    				sendBroadcast(i);*/
    				
    				detectGpsStatus();
    				
    				/*if (mThread.isAlive()) {
    					
    					Log.e(TAG, "thread is alive!");
    					
    				} else {
    					
    					Log.e(TAG, "thread is dead!");
    				}*/
    				
//    				Log.e(TAG, Thread.currentThread().getName());
    				
    				break;
    				
    			default:
    				break;
			}
		}
		
	}
	
	
	public class MyBinder extends Binder {
		
		/*
		 * Get service instance
		 */
		public DWTService getService() {
			
			return DWTService.this;
			
		}
		
	}		// Class MyBinder ends here
	
	
	/*public void setContext(Context context) {
		
		this.mContext = context;
	}*/
	
	public MyHandler getHander() {
		
		return mHandler;
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		
		Log.e(TAG, "Service onBind is called!");
		
		if (intent.hasExtra("position")) {
			
			Log.e(TAG, "position has gone here!");
			
//			Position pos = (Position) intent.getSerializableExtra("position");
//			mBinder.setProximityAlert(pos);
			
		} else if (intent.hasExtra("MoreAct")) {
			
			Log.e(TAG, "intent comes from MoreAct");
		}
		
		/*IBinder result = null;
		if (null == result)
			result = new MyBinder();*/
		
		return mBinder;
//		return null;
	}
	
	@Override
	public boolean onUnbind(Intent intent) {
		
		Log.e(TAG, "service is unbinded!");
		
		return super.onUnbind(intent);
	}
	
	@Override
	public void onCreate() {
		
		super.onCreate();
		
		Log.e(TAG, "Service onCreate is called!");
		
		mGa = (GTDApp) getApplication();
		mHandler = new MyHandler();
		
		IntentFilter filter = new IntentFilter(GPS_ACTION);
		filter.addAction(C.ACTION.LOCATION_ALERT);
		registerReceiver(mReceiver, filter);
		
		mAlarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
		
		mMyLocationMgr = new MyLocationManager(this);
//		mLocationMgr = (LocationManager) getSystemService(LOCATION_SERVICE);
		
		if (mGa.mPosRemind) {
			
			detectGpsStatus();
		}
		
//		checkProvider();
	}
	
	public void toggleGPS() {
		
		Intent gpsIntent = new Intent();
		gpsIntent.setClassName("com.android.settings",
				"com.android.settings.widget.SettingsAppWidgetProvider");
		gpsIntent.addCategory("android.intent.category.ALTERNATIVE");
		gpsIntent.setData(Uri.parse("custom:3"));
		
		try {
			
			PendingIntent.getBroadcast(this, 0, gpsIntent, 0).send();
			
		} catch (CanceledException e) {
			
			e.printStackTrace();
		}
		
	}
	
	public boolean isGPSEnable() {
		
		String str = Settings.Secure.getString(getContentResolver(),
				Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
		
		Log.v(TAG, "GPS status: " + str);
		
		if (str != null) {
			
			return str.contains("gps");
			
		} else {
			
			return false;
		}
		
	}
	
	public void alertOpenGPS(final Context context) {
		
		AlertDialog.Builder builder = new AlertDialog.Builder(context);
		
		builder.setTitle("GPS");
		
		builder.setMessage(" GPS已关闭，无法进行位置提醒，现在打开？ ");
		
		builder.setNegativeButton("取消", new OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
				detectGpsStatus();
				
				dialog.cancel();
			}
			
		});
		
		builder.setPositiveButton("打开", new OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				
				toggleGPS();
				
				Toast.makeText(context, "GPS已开启", Toast.LENGTH_LONG).show();
			}
		});
		
		builder.show();
		
	}
	
	public void checkGPS(Context context) {
		
		if (isGPSEnable()) {
			
			Log.e(TAG, "GPS has been opened!");
			
			// Start GPS service
			if (mGa.mPosRemind) {
				
				mMyLocationMgr.bindGPS();
			}
			
		} else {
			
			Log.e(TAG, "GPS is closed!");
			
			if (mGa.mPosRemind) {
				
				detectGpsStatus();
				
//				Toast.makeText(getApplicationContext(), "open GPS", Toast.LENGTH_LONG).show();
				
				alertOpenGPS(context);
			}
			
		}
		
		return;
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		
		Log.e(TAG, "Service onStartCommand is called!");
		
		/*
		 * phone is booted completely, so restore all alarms
		 */
		if (intent.hasExtra("boot_completed")) {
			
			Log.e(TAG, "now restoring alarms from preferences");
			
			restoreAlarm();
		}
		
		
//		return super.onStartCommand(intent, flags, startId);
		
		// We want this service to continue running until it is explicitly
		// stopped, so return sticky.
		return START_STICKY;
	}
	
	public LocationManager getLocationManager() {
		
		return this.mLocationMgr;
	}
	
	
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		
		super.onDestroy();
		
		Log.e(TAG, "Service onDestroy is called!");
		
//		mIsRunning = false;
		
		/*if (mReceiver != null)
			unregisterReceiver(mReceiver);*/
		
//		unregisterReceiver(mReceiver);
		
//		mAlarmMgr = null;
		
//		mMyLocationMgr.unbindGPS();
	}
	
	
	private void detectGpsStatus() {
		
		final TimerTask task = new TimerTask() {
			
			@Override
			public void run() {
				
				/*if (!mMyLocationMgr.isProviderEnabled()) {		// GPS is disabled
					
					Log.e(TAG, "detecting GPS is disabled, now I give you a notification!");
					
					Intent i = new Intent(DWTService.this, MyReceiver.class);
    				i.setAction(GPS_ACTION);
    				
    				sendBroadcast(i);
					
				} else {		// GPS is enabled
					
					Log.e(TAG, "detecting GPS has been enabled!");
					
					mHandler.sendEmptyMessage(C.GPS.GPS_ENABLED);
				}*/
				
				if (isGPSEnable()) {
					
					Log.e(TAG, "detecting GPS has been enabled!");
					
					mHandler.sendEmptyMessage(C.GPS.GPS_ENABLED);
					
				} else {
					
					Log.e(TAG, "detecting GPS is disabled, now I give you a notification!");
					
					Intent i = new Intent(DWTService.this, MyReceiver.class);
    				i.setAction(GPS_ACTION);
    				
    				sendBroadcast(i);
				}
				
			}
		};
		
		mThread = new Thread(new Runnable() {
			
			@Override
			public void run() {			// After run() is finished, the thread is dead
				
				mTimer = new Timer();
				
				mTimer.schedule(task, 10*1000, 30*60*1000);
			}
			
		});
		
		mThread.start();
		
		// Block current thread until $mThread finish its execution
		try {
			
			mThread.join();
			
		} catch (InterruptedException e1) {
			
			e1.printStackTrace();
		}		
		
		// Main thread sleeps for a while to run $mThread
		/*try {
			Thread.sleep(100);
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			
			e.printStackTrace();
		}*/
		
	}
	
	/*
	 * Set alert on specific location
	 */
	public void setTaskLocationAlert(Position position) {
		
		int size = mID.size();
		for (int i=0; i<size; i++) {
			
			long id = mID.get(i);
			TaskItem task = mGa.getDbta().getTaskItem(id);
			
			mMyLocationMgr.setProximityAlert(position, id, task);
		}
		
	}
	
	public void removeLocAlert(long rowId) {
		
		TaskItem task = mGa.getDbta().getTaskItem(rowId);
		
//		double lat = loc.getLatitude()/1e6;
//		double lng = loc.getLongtitude()/1e6;
			
		Intent intent = new Intent(C.ACTION.LOCATION_ALERT);
		intent.putExtra("row_id", rowId);
		intent.putExtra("task", task);
		
		PendingIntent proximityIntent = PendingIntent.getBroadcast(this,
				0,
				intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
		
		mMyLocationMgr.getLocationManager().removeProximityAlert(proximityIntent);
		
		Log.e(TAG, " location alert of task " + rowId + " has been removed! ");
	}
	
	private void restoreAlarm() {
		
		SharedPreferences sp = getSharedPreferences(SP_ALARM, MODE);
		
		if (sp.contains("exist")) {
//			mID.clear();
//			mCalRemind.clear();
			
			int count = sp.getInt("remind_count", 0);
			if (count == 0)		// no available alarm to restore
				return;
			
			int total = sp.getInt("total_remind", 0);
			for (int i=0; i<total; i++) {
				Calendar cld = Calendar.getInstance();
				
				long taskId = sp.getLong("taskId["+i+"]", -1);
				if (taskId == -1)	// the alarm not exist
					continue;
				
//				mID.add(taskId);
				
				try {
					String remind = sp.getString("remind["+i+"]", "");
					cld.setTime(mSdf.parse(remind));
					
//					mCalRemind.add(cld);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				setSingleAlarm(taskId, cld, i);
			}
			
			Log.e(TAG, "have restored "+count+"alarms");
			
		} else {
			
			Editor edit = sp.edit();
			edit.putBoolean("exist", true);
			edit.putInt("remind_count", 0);			// number of alarms that will go off in future
			edit.putInt("total_remind", 0);		// total number of alarms
			
			edit.commit();
		}
		
	}
	
	/**
	 * Sets a single alarm.
	 *
	 * @param taskId the task id
	 * @param remind the remind time
	 * @param index the index in all alarms
	 */
	public void setSingleAlarm(long taskId, Calendar remind, int index) {
		
		Intent itt = new Intent(DWTService.this, MyReceiver.class);
		itt.setAction(DWTService.ALARMS);
		
		TaskItem task = mGa.getDbta().getTaskItem(taskId);
		itt.putExtra("row_id", taskId);
		itt.putExtra("task", task);
		itt.putExtra("remind_index", index);
		
		PendingIntent pi = PendingIntent.getBroadcast(		// will perform a broadcast
				DWTService.this,
				index,		// identify different alarms
				itt,
				PendingIntent.FLAG_UPDATE_CURRENT);
		
		mAlarmMgr.set(AlarmManager.RTC_WAKEUP, remind.getTimeInMillis(), pi);
	}
	
	public void setTaskID(ArrayList<Long> id) {
		
		this.mID = id;
	}
	
	public void setRemindTime(ArrayList<Calendar> cld) {
		
		this.mCalRemind = cld;
		
		for (int i=0; i<mCalRemind.size(); i++) {
			
			Log.e(TAG, "remind["+i+"]:"+mSdf.format(mCalRemind.get(i).getTime()));
		}
		
	}
	
	public void removeSingleAlarm(long taskId) {
		int i;
		
		SharedPreferences sp = getSharedPreferences(SP_ALARM, MODE);
		int total = sp.getInt("total_remind", -1);
		int count = sp.getInt("remind_count", -1);
		
		if (count == 0)
			return;
		
		for (i=0; i<total; i++) {
			
			long id = sp.getLong("taskId["+i+"]", -1);		// if no such alarm, return -1
			
			if (id == taskId) {
				
    			Editor edit = sp.edit();
    			edit.remove("taskId["+i+"]");
    			edit.remove("remind["+i+"]");
    			edit.putInt("remind_count", count-1);
    			
    			edit.commit();
    			break;
			}
			
		}
		
		if (i >= total)	 {	// not found this task
			Log.e(TAG, "the alarm has been removed or has gone off!");
			return;
		}
		
		Intent itt = new Intent(DWTService.this, MyReceiver.class);
		itt.setAction(DWTService.ALARMS);
		
		TaskItem task = mGa.getDbta().getTaskItem(taskId);
		itt.putExtra("row_id", taskId);
		itt.putExtra("task", task);
		
		PendingIntent pi = PendingIntent.getBroadcast(		// will perform a broadcast
				DWTService.this,
				i,
				itt,
				PendingIntent.FLAG_UPDATE_CURRENT);
		
		mAlarmMgr.cancel(pi);
	}
	
	/**
	 * Sets the alarm.
	 */
	public void setAlarm() {
		if (mCalRemind.size() == 0)		// no alarms set
			return;
		
		Log.e(TAG, "number of alarms is: "+mCalRemind.size());
		
		SharedPreferences sp = getSharedPreferences(SP_ALARM, MODE);
		SharedPreferences.Editor edit = sp.edit();
		
		if (sp.contains("exist") == false) {
			
			edit.putBoolean("exist", true);
			edit.putInt("remind_count", 0);
			edit.putInt("total_remind", 0);
			
			edit.commit();
		}
		
		int count = sp.getInt("remind_count", 0);
		int total = sp.getInt("total_remind", 0);		// get total number of alarms
		
		for (int i=0; i<mCalRemind.size(); i++) {
			
			long taskId = mID.get(i);
			Calendar remind = mCalRemind.get(i);
			Date date = remind.getTime();
			
			setSingleAlarm(taskId, remind, total+i);
			
			// save this alarm to sharedpreferences
			edit.putLong("taskId["+(total+i)+"]", taskId);
			edit.putString("remind["+(total+i)+"]", mSdf.format(date));
			
		}
		
		edit.putInt("remind_count", count+mCalRemind.size());
		edit.putInt("total_remind", total+mCalRemind.size());
		
		edit.commit();
		
		mID.clear();
		mCalRemind.clear();
		
		Log.e(TAG, "alarms have been set!");
		
//		sendBroadcast(itt);
	}
}
